#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sqlite3.h>
#include "structures.h"
#include "../sha2/sha2.h"
#include "db.h"

#define SECTOR_TITLE "select distinct sectorname, privilege from document_level where title = \""
#define SECTOR_ONLY_TITLE "select distinct sectorname from document_level where title = \""
#define USER_TITLE "select sectorname, privilege from user_level where username = \""

static int privilegeCallback(void *, int, char **, char **);
static int privilegeOnlyCallback(void *, int, char **, char **);
static int orderCallback(void *, int, char **, char **);
static int documentAllCallback(void *, int, char **, char **);
static int documentContentCallback(void *, int, char **, char **);
static int authenticateUserCallback(void * , int, char **, char **);
static int keyForUDCallback(void * , int, char **, char **);
static int userSectorCallback(void *, int, char **, char **);
static int privilegeLevelCallback(void *, int, char **, char **);
static int sectorLevelDocCallback(void *, int, char **, char **);
static int userKeyCallback(void *, int, char **, char **);
static int maxLevelCallback(void *, int, char **, char **);

static int getPrivilegeForLevel(char *, char *);

t_privileges *
getSectorsForTitle(char * title) {
       sqlite3 * db;
       char * errMsg;
       int retCode;
       char * query;
       t_privileges * ret;

       ret = (t_privileges *) malloc(sizeof(t_privileges));
       if (ret == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               return NULL;
       }

       ret->maxSize = MAX_SIZE;
       ret->size = 0;
       ret->sectors = (t_privilege **)malloc(sizeof(t_privilege *) * MAX_SIZE);
       if (ret->sectors == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               return NULL;
       }

       retCode = sqlite3_open(DB_NAME, &db);
       if (retCode) {
               fprintf(stderr, "Error while opening DB: %s\n", sqlite3_errmsg(db));
               sqlite3_close(db);
               return NULL;
       }

       query = (char *) malloc((strlen(SECTOR_TITLE) + strlen(title) + strlen("\"") + 1) * sizeof(*query));
       if (query == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               sqlite3_close(db);
               return NULL;
       }

       strcpy(query, SECTOR_TITLE);
       strcat(query, title);
       strcat(query, "\"");

       retCode = sqlite3_exec(db, query, privilegeCallback, ret, &errMsg);
       if (retCode != SQLITE_OK) {
               fprintf(stderr, "SQL Error: %s\n", errMsg);
               sqlite3_free(errMsg);
       }

       sqlite3_close(db);
       return ret;
}

t_privileges *
getOnlySectorsForTitle(char * title) {
       sqlite3 * db;
       char * errMsg;
       int retCode;
       char * query;
       t_privileges * ret;

       ret = (t_privileges *) malloc(sizeof(t_privileges));
       if (ret == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               return NULL;
       }

       ret->maxSize = MAX_SIZE;
       ret->size = 0;
       ret->sectors = (t_privilege **)malloc(sizeof(t_privilege *) * MAX_SIZE);
       if (ret->sectors == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               return NULL;
       }

       retCode = sqlite3_open(DB_NAME, &db);
       if (retCode) {
               fprintf(stderr, "Error while opening DB: %s\n", sqlite3_errmsg(db));
               sqlite3_close(db);
               return NULL;
       }

       query = (char *) malloc((strlen(SECTOR_ONLY_TITLE) + strlen(title) + strlen("\"") + 1) * sizeof(*query));
       if (query == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               sqlite3_close(db);
               return NULL;
       }

       strcpy(query, SECTOR_ONLY_TITLE);
       strcat(query, title);
       strcat(query, "\"");

       retCode = sqlite3_exec(db, query, privilegeOnlyCallback, ret, &errMsg);
       if (retCode != SQLITE_OK) {
               fprintf(stderr, "SQL Error: %s\n", errMsg);
               sqlite3_free(errMsg);
       }

       sqlite3_close(db);
       return ret;
}


static int
privilegeCallback(void * ret, int argc, char ** argv, char ** colName) {
       int i;

       t_privileges * privileges = (t_privileges *) ret;
       if (privileges->size == privileges->maxSize) {
               t_privileges * aux = (t_privileges *) malloc(sizeof(t_privileges));
               if (aux == NULL) {
                       fprintf(stderr, "Error while allocating memory\n");
                       return 1;
               }
               aux->maxSize = privileges->maxSize * 2;
               aux->size = privileges->size;
               aux->sectors = (t_privilege **) (malloc(sizeof(t_privilege *) * aux->maxSize));
               if (aux->sectors == NULL) {
                       fprintf(stderr, "Error while allocating memory\n");
                       return 1;
               }
               
               for (i = 0; i < privileges->size; i++) {
                       aux->sectors[i] = privileges->sectors[i];
               }
               privileges = aux;              
       }

       t_privilege * sector = (t_privilege *) malloc(sizeof(t_privilege));
       if (sector == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               return 1;
       }
       sector->name = (char *) malloc(sizeof(char) * 201);
       if (sector->name == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               return 1;
       }

       strcpy(sector->name, argv[0]);
       sector->order = atoi(argv[1]);

       privileges->sectors[privileges->size] = sector;
       privileges->size++;    

       return 0;
}

static int
privilegeOnlyCallback(void * ret, int argc, char ** argv, char ** colName) {
       int i;

       t_privileges * privileges = (t_privileges *) ret;
       if (privileges->size == privileges->maxSize) {
               t_privileges * aux = (t_privileges *) malloc(sizeof(t_privileges));
               if (aux == NULL) {
                       fprintf(stderr, "Error while allocating memory\n");
                       return 1;
               }
               aux->maxSize = privileges->maxSize * 2;
               aux->size = privileges->size;
               aux->sectors = (t_privilege **) (malloc(sizeof(t_privilege *) * aux->maxSize));
               if (aux->sectors == NULL) {
                       fprintf(stderr, "Error while allocating memory\n");
                       return 1;
               }
               
               for (i = 0; i < privileges->size; i++) {
                       aux->sectors[i] = privileges->sectors[i];
               }
               privileges = aux;              
       }

       t_privilege * sector = (t_privilege *) malloc(sizeof(t_privilege));
       if (sector == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               return 1;
       }
       sector->name = (char *) malloc(sizeof(char) * 201);
       if (sector->name == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               return 1;
       }

       strcpy(sector->name, argv[0]);

       privileges->sectors[privileges->size] = sector;
       privileges->size++;    

       return 0;
}


t_privileges *
getSectorsForUser(char * user) {
       sqlite3 * db;
       char * errMsg;
       int retCode;
       char * query;
       t_privileges * ret;

       ret = (t_privileges *) malloc(sizeof(t_privileges));
       if (ret == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               return NULL;
       }

       ret->maxSize = MAX_SIZE;
       ret->size = 0;
       ret->sectors = (t_privilege **)malloc(sizeof(t_privilege *) * MAX_SIZE);
       if (ret->sectors == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               return NULL;
       }

       retCode = sqlite3_open(DB_NAME, &db);
       if (retCode) {
               fprintf(stderr, "Error while opening DB: %s\n", sqlite3_errmsg(db));
               sqlite3_close(db);
               return NULL;
       }

       query = (char *) malloc((strlen(USER_TITLE) + strlen(user) + strlen("\"") + 1) * sizeof(*query));
       if (query == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               sqlite3_close(db);
               return NULL;
       }

       strcpy(query, USER_TITLE);
       strcat(query, user);
       strcat(query, "\"");

       retCode = sqlite3_exec(db, query, privilegeCallback, ret, &errMsg);
       if (retCode != SQLITE_OK) {
               fprintf(stderr, "SQL Error: %s\n", errMsg);
               sqlite3_free(errMsg);
       }

       sqlite3_close(db);
       return ret;
}

t_privileges *
getLevelsForSector(char * sector) {
       sqlite3 * db;
       char * errMsg;
       int retCode;
       char * query;
       t_privileges * ret;

       ret = (t_privileges *) malloc(sizeof(t_privileges));
       if (ret == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               return NULL;
       }

       ret->maxSize = MAX_SIZE;
       ret->size = 0;
       ret->sectors = (t_privilege **)malloc(sizeof(t_privilege *) * MAX_SIZE);
       if (ret->sectors == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               return NULL;
       }

       retCode = sqlite3_open(DB_NAME, &db);
       if (retCode) {
               fprintf(stderr, "Error while opening DB: %s\n", sqlite3_errmsg(db));
               sqlite3_close(db);
               return NULL;
       }


       query = (char *) malloc(1000);
       if (query == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               sqlite3_close(db);
               return NULL;
       }

       sprintf(query,"select levelname, privilege from level where sectorname = \"%s\"",sector);
       
       retCode = sqlite3_exec(db, query, privilegeCallback, ret, &errMsg);
       if (retCode != SQLITE_OK) {
               fprintf(stderr, "SQL Error: %s\n", errMsg);
               sqlite3_free(errMsg);
       }

       sqlite3_close(db);
       return ret;
}



t_documents *
getAllDocuments(char * filter, int * amount) {
       sqlite3 * db;
       char * errMsg;
       char count[10];
       int retCode;
       char query[150] = {0};
       t_documents * ret = NULL;

       retCode = sqlite3_open(DB_NAME, &db);
       if (retCode) {
               fprintf(stderr, "Error while opening DB: %s\n", sqlite3_errmsg(db));
               sqlite3_close(db);
               return NULL;
       }

       ret = (t_documents *) malloc(sizeof(t_documents));
       if (ret == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               sqlite3_close(db);
               return NULL;
       }
       ret->size = 0;
       ret->maxSize = MAX_SIZE;
       ret->documents = (t_document **) malloc(sizeof(t_document *) * MAX_SIZE);
       if (ret->documents == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               sqlite3_close(db);
               return NULL     ;
       }
       if(!strcmp(filter,""))
       {
               sprintf(query, "select distinct title from document");
       }
       else
       {
               sprintf(query, "select distinct title from document where title like \"%%%s%%\"",filter);
               printf("select distinct title from document where title like \"%%%s%%\"",filter);
       }
       retCode = sqlite3_exec(db, query, documentAllCallback, ret, &errMsg);
       if (retCode != SQLITE_OK) {
               fprintf(stderr, "SQL Error: %s\n", errMsg);
               sqlite3_free(errMsg);
       }
       
       if(!strcmp(filter,""))
                       sprintf(query, "select count(distinct title) from document");
       else
                       sprintf(query, "select count(distinct title) from document where title like \"%%%s%%\"",filter);
       
       retCode = sqlite3_exec(db, query, authenticateUserCallback, count, &errMsg);

       if (retCode != SQLITE_OK) {
               fprintf(stderr, "SQL Error AUt: %s\n", errMsg);
               sqlite3_free(errMsg);
               return NULL;
       }
               
               
       *amount=atoi(count);

       sqlite3_close(db);
       return ret;
}

static int
documentAllCallback(void * ret, int argc, char ** argv, char ** columnname) {
       t_documents * docs;
       int i;

       docs = (t_documents *) ret;
       if (docs->size == docs->maxSize) {
               t_documents * aux = (t_documents *) malloc(sizeof(t_documents));
               if (aux == NULL) {
                       fprintf(stderr, "Error while allocating memory\n");
                       return 1;
               }
               aux->maxSize = docs->maxSize * 2;
               aux->size = docs->size;
               aux->documents = (t_document **) (malloc(sizeof(t_document *) * aux->maxSize));
               if (aux->documents == NULL) {
                       fprintf(stderr, "Error while allocating memory\n");
                       return 1;
               }
               
               for (i = 0; i < docs->size; i++) {
                       aux->documents[i] = docs->documents[i];
               }
               docs = aux;            
       }

       if (argc > 0) {
               t_document * document = (t_document *) malloc(sizeof(t_document));
               if (document == NULL) {
                       fprintf(stderr, "Error while allocating memory\n");
                       return 1;
               }

               strcpy(document->title, argv[0]);

               docs->documents[docs->size] = document;
               docs->size++;
       }

       return 0;
}

char *
getDocumentContent(char * title, char * sector, char * level) {
       sqlite3 * db;
       char * errMsg;
       int retCode;
       char query[1050] = {0};
       char * doc;
	int privilege;

       retCode = sqlite3_open(DB_NAME, &db);
       if (retCode) {
               fprintf(stderr, "Error while opening DB: %s\n", sqlite3_errmsg(db));
               sqlite3_close(db);
               return NULL;
       }

       doc = (char *) malloc(sizeof(char) * 3001);
       if (doc == NULL) {
               fprintf(stderr, "Error while opening DB: %s\n", sqlite3_errmsg(db));
               sqlite3_close(db);
               return NULL;
       }
       strcpy(doc, "");

privilege = getPrivilegeForLevel(sector, level);

       sprintf(query, "select document.content, document.bytes from document, document_level where document.title = document_level.title and document_level.sectorname = \"%s\" and document_level.privilege = %d and document.title = \"%s\" and document.last = (select max(last) from document where title = \"%s\")", sector, privilege, title, title);
       retCode = sqlite3_exec(db, query, documentContentCallback, doc, &errMsg);
       if (retCode != SQLITE_OK) {
               fprintf(stderr, "SQL Error: %s\n", errMsg);
               sqlite3_free(errMsg);
       }

       sqlite3_close(db);
       return doc;
}

static int
documentContentCallback(void * ret, int argc, char ** argv, char ** columnname) {
       memcpy((char *)ret, argv[0], atoi(argv[1]));
       return 0;
}

void
addUser(char * user, char * psw, char * key) {
       sqlite3 * db;
       char * errMsg;
       int retCode;
       char query[1500] = {0};
       char cryptedPsw[SHA256_DIGEST_SIZE + 1] = {0};
       char cryptedPswAscii[SHA256_DIGEST_SIZE + 1] = {0};

       retCode = sqlite3_open(DB_NAME, &db);
       if (retCode) {
               fprintf(stderr, "Error while opening DB: %s\n", sqlite3_errmsg(db));
               sqlite3_close(db);
               return;
       }
       
       sha256((unsigned char *) psw, strlen(psw), (unsigned char *) cryptedPsw);
       sha2562Ascii(cryptedPswAscii, cryptedPsw);
       sprintf(query, "insert into user values(\"%s\", \"%s\", \"%s\")", user, cryptedPswAscii, key);
       
       retCode = sqlite3_exec(db, query, NULL, 0, &errMsg);
       if (retCode != SQLITE_OK) {
               fprintf(stderr, "SQL Error: %s\n", errMsg);
               sqlite3_free(errMsg);
       }

       sqlite3_close(db);
       return;
}

void
addSector(char * sectorname, char * levels) {
       sqlite3 * db;
       char * errMsg;
       int retCode;
       char * query;
       char * token;
       int order = 1;


       retCode = sqlite3_open(DB_NAME, &db);
       if (retCode) {
               fprintf(stderr, "Error while opening DB: %s\n", sqlite3_errmsg(db));
               sqlite3_close(db);
               return;
       }

       query = (char *) calloc(151, sizeof(*query));
       if (query == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               return;
       }

       sprintf(query, "insert into sector values(\"%s\")", sectorname);
       retCode = sqlite3_exec(db, query, NULL, 0, &errMsg);
       if (retCode != SQLITE_OK) {
               fprintf(stderr, "SQL Error: %s\n", errMsg);
               sqlite3_free(errMsg);
               return;
       }

       while ((token = strtok(levels, " ")) != NULL) {
               levels = NULL;
               
               query = (char *) calloc(151, sizeof(*query));
               if (query == NULL) {
                       fprintf(stderr, "Error while allocating memory\n");
                       return;
               }

               sprintf(query, "insert into level values(%d, \"%s\", \"%s\")", order++, sectorname, token);
               retCode = sqlite3_exec(db, query, NULL, 0, &errMsg);
               if (retCode != SQLITE_OK) {
                       fprintf(stderr, "SQL Error: %s\n", errMsg);
                       sqlite3_free(errMsg);
               }
       }

       sqlite3_close(db);
       return;
}

void
addPrivilege(char * user, char * sectorname, char * level) {
       sqlite3 * db;
       char * errMsg;
       int retCode;
       char * query;
       int priv;

       retCode = sqlite3_open(DB_NAME, &db);
       if (retCode) {
               fprintf(stderr, "Error while opening DB: %s\n", sqlite3_errmsg(db));
               sqlite3_close(db);
               return;
       }

       query = (char *) calloc(151, sizeof(*query));
       if (query == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               return;
       }

       sprintf(query, "select privilege from level where sectorname = \"%s\" and levelname = \"%s\"", sectorname, level);

       retCode = sqlite3_exec(db, query, orderCallback, &priv, &errMsg);
       if (retCode != SQLITE_OK) {
               fprintf(stderr, "SQL Error: %s\n", errMsg);
               sqlite3_free(errMsg);
               return;
       }

       query = (char *) calloc(151, sizeof(*query));
       if (query == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               return;
       }

       sprintf(query, "insert into user_level values(\"%s\", \"%s\", %d)", user, sectorname, priv);
       retCode = sqlite3_exec(db, query, NULL, 0, &errMsg);
       if (retCode != SQLITE_OK) {
               fprintf(stderr, "SQL Error: %s\n", errMsg);
               sqlite3_free(errMsg);
               return;
       }
       
       sqlite3_close(db);
       return;
}

static int
orderCallback(void * ret, int argc, char ** argv, char ** columnName) {
       int * aux;

       aux = (int *) ret;
       *aux = atoi(argv[0]);

       return 0;
}

void
delPrivilege(char * user, char * sectorname) {
       sqlite3 * db;
       char * errMsg;
       int retCode;
       char * query;

       retCode = sqlite3_open(DB_NAME, &db);
       if (retCode) {
               fprintf(stderr, "Error while opening DB: %s\n", sqlite3_errmsg(db));
               sqlite3_close(db);
               return;
       }

       query = (char *) calloc(151, sizeof(*query));
       if (query == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               return;
       }

       sprintf(query, "delete from user_level where username = \"%s\" and sectorname = \"%s\"", user, sectorname);
       retCode = sqlite3_exec(db, query, NULL, 0, &errMsg);
       if (retCode != SQLITE_OK) {
               fprintf(stderr, "SQL Error: %s\n", errMsg);
               sqlite3_free(errMsg);
               return;
       }
       
       sqlite3_close(db);
       return;
}


int
authenticateUser(char * user, char * hash) {
       sqlite3 * db;
       char * errMsg;
       int retCode;
       char * query;
       char count[10];

       retCode = sqlite3_open(DB_NAME, &db);
               
       if (retCode) {
               fprintf(stderr, "Error while opening DB: %s\n", sqlite3_errmsg(db));
               sqlite3_close(db);
               return 0;
       }
               
       query = (char *) calloc(151, sizeof(*query));
       if (query == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               return 0;
       }
               
       sprintf(query, "select count(*) from user where username = \"%s\" and password = \"%s\"", user, hash);
       retCode = sqlite3_exec(db, query, authenticateUserCallback, count, &errMsg);

       if (retCode != SQLITE_OK) {
               fprintf(stderr, "SQL Error AUt: %s\n", errMsg);
               sqlite3_free(errMsg);
               return 0;
       }
       
       sqlite3_close(db);
       return atoi(count);
}

static int
authenticateUserCallback(void * ret, int argc, char ** argv, char ** columnname) {
       memcpy((char *)ret,argv[0],sizeof(char *));
       return 0;
}

int
saveUserDocumentKey(char * user, char * title, char * key) {
       sqlite3 * db;
       char * errMsg;
       int retCode;
       char * query;

       retCode = sqlite3_open(DB_NAME, &db);
       if (retCode) {
               fprintf(stderr, "Error while opening DB: %s\n", sqlite3_errmsg(db));
               sqlite3_close(db);
               return 0;
       }

       query = (char *) calloc(1551, sizeof(*query));
       if (query == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               return 0;
       }

       /*char init[400] = {0};
       char end[400] = {0};
       sprintf(init, "insert into user_document_key values(\"%s\", \"%s\", \"X'", user, title);
       memcpy(query, init, strlen(init));
       memcpy(query + strlen(init), key, 256);
       sprintf(end, "'\")");
       memcpy(query + strlen(init) + 256, end, strlen(end));*/


       sprintf(query, "insert into user_document_key(username, title, key) values(\"%s\", \"%s\", ?)", user, title);
       sqlite3_stmt * stmt;
       retCode = sqlite3_prepare_v2(db, query, 1551, &stmt, NULL);
       if (retCode != SQLITE_OK) {
               fprintf(stderr, "Error while preparing statement-Error Code: %d\n", retCode);
               return 0;
       }
       retCode = sqlite3_bind_blob(stmt, 1, key, 256, SQLITE_TRANSIENT);
       if (retCode != SQLITE_OK) {
               fprintf(stderr, "BLOB binding failed.\n");
               return 0;
       }

       retCode = sqlite3_step(stmt);
       if (retCode != SQLITE_DONE) {
               fprintf(stderr, "Error while stepping\n");
               return 0;
       }
       /*retCode = sqlite3_exec(db, query, NULL, 0, &errMsg);
       if (retCode != SQLITE_OK) {
               fprintf(stderr, "SQL Error: %s\n", errMsg);
               sqlite3_free(errMsg);
               return 0;
       }*/
       
       sqlite3_close(db);
       return 1;
}

char *
getKeyForUserDocument(char * user, char * title) {
       sqlite3 * db;
       char * errMsg;
       int retCode;
       char * query;
       char * ret;

       retCode = sqlite3_open(DB_NAME, &db);
       if (retCode) {
               fprintf(stderr, "Error while opening DB: %s\n", sqlite3_errmsg(db));
               sqlite3_close(db);
               return 0;
       }

       query = (char *) calloc(551, sizeof(*query));
       if (query == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               return NULL;
       }

       ret = (char *) malloc(sizeof(*query) * 1001);
       if (ret == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               return NULL;
       }

       sprintf(query, "select key from user_document_key where username = \"%s\" and title = \"%s\" and last = (select max(last) from user_document_key where title = \"%s\" and username = \"%s\")", user, title, title, user);
       retCode = sqlite3_exec(db, query, keyForUDCallback, ret, &errMsg);
       if (retCode != SQLITE_OK) {
               fprintf(stderr, "SQL Error: %s\n", errMsg);
               sqlite3_free(errMsg);
               return NULL;
       }
       
       sqlite3_close(db);
       return ret;
}

static int
keyForUDCallback(void * ret, int argc, char ** argv, char ** columnname) {
       char * key;
       key = (char *) ret;
       memcpy(key, argv[0], 256);
       return 0;
}

t_users *
getUsersForSector(char * sector, int privilege) {
       sqlite3 * db;
       char * errMsg;
       int retCode;
       char * query;
       t_users * ret;

       ret = (t_users *) malloc(sizeof(t_users));
       if (ret == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               return NULL;
       }

       ret->maxSize = MAX_SIZE;
       ret->size = 0;
       ret->users = (t_user **)malloc(sizeof(t_user *) * MAX_SIZE);
       if (ret->users == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               return NULL;
       }

       retCode = sqlite3_open(DB_NAME, &db);
       if (retCode) {
               fprintf(stderr, "Error while opening DB: %s\n", sqlite3_errmsg(db));
               sqlite3_close(db);
               return NULL;
       }

       query = (char *) calloc(151, sizeof(*query));
       if (query == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               return NULL;
       }

       sprintf(query, "select username from user_level where sectorname = \"%s\" and privilege = %d", sector, privilege);
       retCode = sqlite3_exec(db, query, userSectorCallback, ret, &errMsg);
       if (retCode != SQLITE_OK) {
               fprintf(stderr, "SQL Error: %s\n", errMsg);
               sqlite3_free(errMsg);
       }

       sqlite3_close(db);
       return ret;
}

static int
userSectorCallback(void * ret, int argc, char ** argv, char ** colName) {
       int i;

       t_users * allUsers = (t_users *) ret;
       if (allUsers->size == allUsers->maxSize) {
               t_users * aux = (t_users *) malloc(sizeof(t_users));
               if (aux == NULL) {
                       fprintf(stderr, "Error while allocating memory\n");
                       return 1;
               }
               aux->maxSize = allUsers->maxSize * 2;
               aux->size = allUsers->size;
               aux->users = (t_user **) (malloc(sizeof(t_user *) * aux->maxSize));
               if (aux->users == NULL) {
                       fprintf(stderr, "Error while allocating memory\n");
                       return 1;
               }
               
               for (i = 0; i < allUsers->size; i++) {
                       aux->users[i] = allUsers->users[i];
               }
               allUsers = aux;        
       }

       t_user * aUser = (t_user *) malloc(sizeof(t_user));
       if (aUser == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               return 1;
       }
       aUser->username = (char *) malloc(sizeof(char) * 9);
       if (aUser->username == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               return 1;
       }

       strcpy(aUser->username, argv[0]);

       allUsers->users[allUsers->size] = aUser;
       allUsers->size++;      

       return 0;
}

int
saveDocument(char * title, char * sector, char * level, char * content, int size) {
       sqlite3 * db;
       char * errMsg;
       int retCode;
       char * query;
       int privilege;

       retCode = sqlite3_open(DB_NAME, &db);
       if (retCode) {
               fprintf(stderr, "Error while opening DB: %s\n", sqlite3_errmsg(db));
               sqlite3_close(db);
               return 0;
       }

       query = (char *) calloc(3551, sizeof(*query));
       if (query == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               return 0;
       }

       /*char init[501] = {0};
       char end[501] = {0};
       sprintf(init, "insert into document(title, content, bytes) values(\"%s\", \"", title);
       memcpy(query, init, strlen(init));
       memcpy(query + strlen(init), content, size);
       sprintf(end, "\", %d)", size);
       memcpy(query + strlen(init) + size, end, strlen(end));*/

       //sprintf(query, "insert into document(title, content, bytes) values(\"%s\", \"%s\", %d)", title, content, size);
       //retCode = sqlite3_exec(db, query, NULL, 0, &errMsg);
       /*There's no SQLITE_OK check because if it fails, it's because the document already exists in that table*/

       /*query = (char *) calloc(151, sizeof(*query));
       if (query == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               return 0;
       }*/
       
       sprintf(query, "insert into document(title, content, bytes) values(\"%s\", ?, \"%d\")", title, size);
       sqlite3_stmt *  stmt;
       sqlite3_prepare_v2(db, query, 3551, &stmt, NULL);
       sqlite3_bind_blob(stmt, 1, content, size, SQLITE_TRANSIENT);
       sqlite3_step(stmt);
       
       privilege = getPrivilegeForLevel(sector, level);


       query = (char *) calloc(3551, sizeof(*query));
       if (query == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               return 0;
       }

       sprintf(query, "insert into document_level values(\"%s\", %d, \"%s\")", title, privilege, sector);
       retCode = sqlite3_exec(db, query, NULL, 0, &errMsg);
       if (retCode != SQLITE_OK) {
               fprintf(stderr, "SQL Error: %s\n", errMsg);
               sqlite3_free(errMsg);
       }

       sqlite3_close(db);
       return 1;
}

static int
getPrivilegeForLevel(char * sector, char * level) {
       sqlite3 * db;
       char * errMsg;
       int retCode;
       char * query;
       int order = -1;

       retCode = sqlite3_open(DB_NAME, &db);
       if (retCode) {
               fprintf(stderr, "Error while opening DB: %s\n", sqlite3_errmsg(db));
               sqlite3_close(db);
               return order;
       }

       query = (char *) calloc(3151, sizeof(*query));
       if (query == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               return order;
       }

       sprintf(query, "select privilege from level where sectorname = \"%s\" and levelname = \"%s\"", sector, level);
       retCode = sqlite3_exec(db, query, privilegeLevelCallback, &order, &errMsg);
       if (retCode != SQLITE_OK) {
               fprintf(stderr, "SQL Error: %s\n", errMsg);
               sqlite3_free(errMsg);
       }
       
       sqlite3_close(db);
       return order;
}

static int
privilegeLevelCallback(void * ret, int argc, char ** argv, char ** columnname) {
       int * order;
       order = (int *) ret;

       *order = atoi(argv[0]);
       return 0;
}

char *
getLevelForDocumentSector(char * title, char * sector) {
       sqlite3 * db;
       char * errMsg;
       int retCode;
       char * query;
       char * ret;

       retCode = sqlite3_open(DB_NAME, &db);
       if (retCode) {
               fprintf(stderr, "Error while opening DB: %s\n", sqlite3_errmsg(db));
               sqlite3_close(db);
               return NULL;
       }

       ret = (char *) malloc(sizeof(char) * 201);
       if (ret == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               sqlite3_close(db);
               return NULL;
       }

       query = (char *) calloc(501, sizeof(*query));
       if (query == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               sqlite3_close(db);
               return NULL;
       }

       sprintf(query, "select level.levelname from document_level, level where document_level.title = \"%s\" and document_level.sectorname = level.sectorname and document_level.privilege = level.privilege and document_level.sectorname = \"%s\"", title, sector);
       retCode = sqlite3_exec(db, query, sectorLevelDocCallback, ret, &errMsg);
       if (retCode != SQLITE_OK) {
               fprintf(stderr, "SQL Error: %s\n", errMsg);
               sqlite3_free(errMsg);
               return ret;
       }
       
       sqlite3_close(db);
       return ret;
}

static int
sectorLevelDocCallback(void * ret, int argc, char ** argv, char ** columnname) {
       char * dInfo;

       dInfo = (char *) ret;
       strcpy(ret, argv[0]);
       return 0;
}

char *
getUserKey(char * user) {
       sqlite3 * db;
       char * errMsg;
       int retCode;
       char * query;
       char * ret;

       retCode = sqlite3_open(DB_NAME, &db);
       if (retCode) {
               fprintf(stderr, "Error while opening DB: %s\n", sqlite3_errmsg(db));
               sqlite3_close(db);
               return NULL;
       }

       ret = (char *) malloc(sizeof(char) * 1025);
       if (ret == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               sqlite3_close(db);
               return NULL;
       }

       query = (char *) calloc(151, sizeof(*query));
       if (query == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               sqlite3_close(db);
               return NULL;
       }

       sprintf(query, "select publickey from user where username = \"%s\"", user);
       retCode = sqlite3_exec(db, query, userKeyCallback, ret, &errMsg);
       if (retCode != SQLITE_OK) {
               fprintf(stderr, "SQL Error: %s\n", errMsg);
               sqlite3_free(errMsg);
               return ret;
       }
       
       sqlite3_close(db);
       return ret;
}

static int
userKeyCallback(void * ret, int argc, char ** argv, char ** columnname) {
       char * userKey;

       userKey = (char *) ret;
       memcpy(userKey, argv[0], 1024);
       userKey[1024] = 0;

       return 0;
}

char *
getPrivilegeUserSector(char * user, char * sector) {
       sqlite3 * db;
       char * errMsg;
       int retCode;
       char * query;
       char * ret;

       retCode = sqlite3_open(DB_NAME, &db);
       if (retCode) {
               fprintf(stderr, "Error while opening DB: %s\n", sqlite3_errmsg(db));
               sqlite3_close(db);
               return NULL;
       }

       ret = (char *) malloc(sizeof(char) * 201);
       if (ret == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               sqlite3_close(db);
               return NULL;
       }

       query = (char *) calloc(501, sizeof(*query));
       if (query == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               sqlite3_close(db);
               return NULL;
       }

       sprintf(query, "select level.levelname from user_level, level where user_level.username = \"%s\" and user_level.sectorname = level.sectorname and user_level.privilege = level.privilege and user_level.sectorname = \"%s\"", user, sector);
       retCode = sqlite3_exec(db, query, sectorLevelDocCallback, ret, &errMsg);
       if (retCode != SQLITE_OK) {
               fprintf(stderr, "SQL Error: %s\n", errMsg);
               sqlite3_free(errMsg);
               return ret;
       }
       
       sqlite3_close(db);
       return ret;
}


void
lucyInTheSkyWithDiamonds(char * sql) {
       sqlite3 * db;
       char * errMsg;
       int retCode;
       
       retCode = sqlite3_open(DB_NAME, &db);
       if (retCode) {
               fprintf(stderr, "Error while opening DB: %s\n", sqlite3_errmsg(db));
               sqlite3_close(db);
               return;
       }

       retCode = sqlite3_exec(db, sql, NULL, 0, &errMsg);
       if (retCode != SQLITE_OK) {
               fprintf(stderr, "SQL Error: %s\n", errMsg);
               sqlite3_free(errMsg);
               return;
       }

       sqlite3_close(db);
       return;
}

int
getMaxLevel(char * sector) {
       sqlite3 * db;
       char * errMsg;
       int retCode;
       char * query;
       int * ret;

       retCode = sqlite3_open(DB_NAME, &db);
       if (retCode) {
               fprintf(stderr, "Error while opening DB: %s\n", sqlite3_errmsg(db));
               sqlite3_close(db);
               return 0;
       }

       ret = (int *) malloc(sizeof(int) * 1);
       if (ret == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               sqlite3_close(db);
               return 0;
       }

       query = (char *) calloc(501, sizeof(*query));
       if (query == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               sqlite3_close(db);
               return 0;
       }

       sprintf(query, "select max(privilege) from level where sectorname = \"%s\"", sector);
       retCode = sqlite3_exec(db, query, maxLevelCallback, ret, &errMsg);
       if (retCode != SQLITE_OK) {
               fprintf(stderr, "SQL Error: %s\n", errMsg);
               sqlite3_free(errMsg);
               return *ret;
       }
       
       sqlite3_close(db);
       return *ret;
}

static int
maxLevelCallback(void * ret, int argc, char ** argv, char ** columnname) {
       int * max;

       max = (int *) ret;
       *max = atoi(argv[0]);
       return 0;
}

int
getDocumentSize(char * title) {
       sqlite3 * db;
       char * errMsg;
       int retCode;
       char * query;
       int * ret;

       retCode = sqlite3_open(DB_NAME, &db);
       if (retCode) {
               fprintf(stderr, "Error while opening DB: %s\n", sqlite3_errmsg(db));
               sqlite3_close(db);
               return 0;
       }

       ret = (int *) malloc(sizeof(int) * 1);
       if (ret == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               sqlite3_close(db);
               return 0;
       }

       query = (char *) calloc(501, sizeof(*query));
       if (query == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               sqlite3_close(db);
               return 0;
       }

       sprintf(query, "select bytes from document where title = \"%s\" and last = (select max(last) from document where title = \"%s\")", title, title);
       retCode = sqlite3_exec(db, query, maxLevelCallback, ret, &errMsg);
       if (retCode != SQLITE_OK) {
               fprintf(stderr, "SQL Error: %s\n", errMsg);
               sqlite3_free(errMsg);
               return *ret;
       }
       
       sqlite3_close(db);
       return *ret;
}

int
setDocumentLevel(char * title, char * sectorname, char * level) {
       sqlite3 * db;
       char * errMsg;
       int retCode;
       char * query;
       int priv;

       retCode = sqlite3_open(DB_NAME, &db);
       if (retCode) {
               fprintf(stderr, "Error while opening DB: %s\n", sqlite3_errmsg(db));
               sqlite3_close(db);
               return 0;
       }

       query = (char *) calloc(151, sizeof(*query));
       if (query == NULL) {
               fprintf(stderr, "Error while allocating memory\n");
               return 0;
       }

       sprintf(query, "insert into document_level values(\"%s\", \"%s\", \"%s\")", title, level, sectorname);
       retCode = sqlite3_exec(db, query, NULL, 0, &errMsg);
       if (retCode != SQLITE_OK) {
               fprintf(stderr, "SQL Error: %s\n", errMsg);
               sqlite3_free(errMsg);
               return 0;
       }
       
       sqlite3_close(db);
       return 1;

}
t_users * getPrivAboveLevel(char * sectorname, char * level)
{
               sqlite3 * db;
               char * errMsg;
               int retCode;
               char * query;
               t_users * ret;
               int privilege;

               ret = (t_users *) malloc(sizeof(t_users));
               if (ret == NULL) {
                       fprintf(stderr, "Error while allocating memory\n");
                       return NULL;
               }

               ret->maxSize = MAX_SIZE;
               ret->size = 0;
               ret->users = (t_user **)malloc(sizeof(t_user *) * MAX_SIZE);
               if (ret->users == NULL) {
                       fprintf(stderr, "Error while allocating memory\n");
                       return NULL;
               }

               retCode = sqlite3_open(DB_NAME, &db);
               if (retCode) {
                       fprintf(stderr, "Error while opening DB: %s\n", sqlite3_errmsg(db));
                       sqlite3_close(db);
                       return NULL;
               }

               query = (char *) calloc(151, sizeof(*query));
               if (query == NULL) {
                       fprintf(stderr, "Error while allocating memory\n");
                       return NULL;
               }
               
               privilege = getPrivilegeForLevel(sectorname, level);

               sprintf(query, "select username from user_level where sectorname = \"%s\" and privilege >= %d", sectorname, privilege);
               retCode = sqlite3_exec(db, query, userSectorCallback, ret, &errMsg);
               if (retCode != SQLITE_OK) {
                       fprintf(stderr, "SQL Error: %s\n", errMsg);
                       sqlite3_free(errMsg);
               }

               sqlite3_close(db);
               return ret;
}